home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 127 / maccd 127.iso / software / osx-graphicviewer_folder.sit / osx-graphicviewer Folder / Graphic Viewer.source < prev    next >
Encoding:
Text File  |  2005-03-06  |  54.1 KB  |  2,476 lines  |  [TEXT/????]

  1. MyApp.LoadPrefs:
  2. Sub LoadPrefs()
  3.   WColor.LoadPrefs
  4.   WInfo.LoadPrefs
  5.   WMagnify.LoadPrefs
  6. End Sub
  7.  
  8. MyApp.newWindow:
  9. Sub newWindow(pi as Pic)
  10.   windowlist.append pi.winid
  11.   windowlistrefs.append new WindowItem
  12.   pi.setWindow(window_x, window_y)
  13.   window_x = window_x + window_incr
  14.   window_y = window_y + window_incr
  15. End Sub
  16.  
  17. MyApp.WindowStart:
  18. Sub WindowStart()
  19.   ' set up for window operations
  20.   dim i as integer
  21.   #if TargetWin32 then
  22.     window_left = 10
  23.     window_right = window_left + MDIWindow.Width
  24.     window_top = 10 + window_topmargin
  25.     window_bottom = window_top + MDIWindow.Height
  26.   #else
  27.     window_left = Screen(0).AvailableLeft
  28.     window_right = window_left + Screen(0).AvailableWidth
  29.     window_top = Screen(0).AvailableTop + window_topmargin
  30.     window_bottom = window_top + Screen(0).AvailableHeight
  31.   #endif
  32.   window_x = window_left
  33.   window_y = window_top
  34.   window_count = 0
  35.   for i = 0 to WindowCount - 1
  36.     if WindowPic(i) then
  37.       window_count = window_count + 1
  38.     end
  39.   next
  40. End Sub
  41.  
  42. MyApp.WindowPic:
  43. Function WindowPic(i as integer) As boolean
  44.   return Window(i) isa Pic and Window(i).Title <> "##"
  45. End Function
  46.  
  47. MyApp.getWindowName:
  48. Function getWindowName(wi as integer) As string
  49.   dim i as integer
  50.   dim pi as Pic
  51.   for i = 0 to WindowCount - 1
  52.     if WindowPic(i) then
  53.       pi = Pic(Window(i))
  54.       if pi.winid = wi then
  55.         return Window(i).Title
  56.       end
  57.     end
  58.   next
  59.   return "window #" + str(wi)
  60. End Function
  61.  
  62. MyApp.WindowClose:
  63. Sub WindowClose(pi as Pic)
  64.   dim i as integer
  65.   for i = 1 to Ubound(windowlist)
  66.     if windowlist(i) = pi.winid then
  67.       windowlist(i) = -1
  68.       WindowItem(i).Visible = false
  69.     end
  70.   next
  71. End Sub
  72.  
  73. MyApp.Close:
  74. Sub Close()
  75.   isquitting = true
  76.   Pool.Save
  77. End Sub
  78.  
  79. MyApp.OpenDocument:
  80. Sub OpenDocument(item As FolderItem)
  81.   Dim pi as Pic
  82.   Dim p as Picture
  83.   Dim mi as MenuItem
  84.   
  85.   pi = new Pic
  86.   if pi <> Nil then
  87.     p = item.OpenAsPicture
  88.     if p <> Nil then
  89.       pi.setPic(item, p)
  90.       openrecentlist.append item
  91.       if Ubound(openrecentlist) > 0 then
  92.         mi = new OpenRecentItem
  93.       end
  94.       newWindow(pi)
  95.     else
  96.       MsgBox "Unable to read image from " + item.Name
  97.     end
  98.   else
  99.     MsgBox "Unable to create window for " + item.Name
  100.   end
  101. End Sub
  102.  
  103. MyApp.EnableMenuItems:
  104. Sub EnableMenuItems()
  105.   dim i as integer
  106.   
  107.   #if TargetWin32 then
  108.     FilePrint.Enable
  109.   #endif
  110.   #if TargetLinux then
  111.     FilePrint.Enable
  112.   #endif
  113.   
  114.   if Ubound(openrecentlist) >= 0 then
  115.     FileOpenRecent.Enable
  116.   end
  117.   for i = 0 to Ubound(openrecentlist)
  118.     OpenRecentItem(i).Text = openrecentlist(i).Name
  119.     OpenRecentItem(i).Enable
  120.   next
  121.   
  122.   if Ubound(openrecentlist) >= 0 then
  123.     FileOpenRecent.Enable
  124.   end
  125.   for i = 0 to Ubound(openrecentlist)
  126.     OpenRecentItem(i).Text = openrecentlist(i).Name
  127.     OpenRecentItem(i).Enable
  128.   next
  129.   
  130.   if UBound(windowlist) > 0 then
  131.     WindowArrangeStaggered.Enable
  132.     WindowArrangeLefttoRight.Enable
  133.     WindowArrangeToptoBottom.Enable
  134.     WindowArrangeTiled.Enable
  135.   end
  136.   
  137.   WindowItem(0).Text = "-"
  138.   WindowItem(0).Enabled = false
  139.   for i = 1 to Ubound(windowlist)
  140.     if windowlist(i) >= 0 then
  141.       WindowItem(i).Text = getWindowName(windowlist(i))
  142.       WindowItem(i).Enable
  143.       if windowlist(i) = App.w.getFront then
  144.         WindowItem(i).Checked = true
  145.       else
  146.         WindowItem(i).Checked = false
  147.       end
  148.     end
  149.   next
  150. End Sub
  151.  
  152. MyApp.Open:
  153. Sub Open()
  154.   isquitting = false
  155.   
  156.   imagefilter = "image/pict;image/gif;image/jpeg;image/png;image/tiff;image/x-bmp;image/x-pict;image/x-png;image/x-tiff"
  157.   
  158.   WColor.Hide
  159.   WInfo.Hide
  160.   WMagnify.Hide
  161.   if not Fin.Init("com.finseth", "Graphic Viewer", "GraphicViewer") then Quit
  162.   
  163.   FC = new FileColors
  164.   if FC = Nil then
  165.     MsgBox "Can't create FC"
  166.     Quit
  167.   end
  168.   if not FC.Load("web-colors.txt") then
  169.   end
  170.   
  171.   pbt = new PBThread
  172.   if pbt = Nil then
  173.     MsgBox "Can't create PB thread"
  174.     Quit
  175.   end
  176.   
  177.   sst = new SSThread
  178.   if sst = Nil then
  179.     MsgBox "Can't create SS thread"
  180.     Quit
  181.   end
  182.   
  183.   if w = Nil then
  184.     w = new WindowList
  185.     if w = Nil then
  186.       MsgBox "Can't create WindowList"
  187.       Quit
  188.     end
  189.     w.init
  190.   end
  191.   
  192.   LoadPrefs
  193.   
  194.   #if targetWin32 then
  195.     if FileQuit <> Nil then
  196.       FileQuit.Text = "E&xit"
  197.       FileQuit.CommandKey =  ""
  198.       WinBase.Visible = true
  199.     end
  200.   #endif
  201.   #if TargetLinux then
  202.     WinBase.Visible = true
  203.   #endif
  204.   
  205.   window_topmargin = 40
  206.   
  207.   window_x = 10
  208.   window_y = 10 + window_topmargin
  209.   window_incr = 30
  210. End Sub
  211.  
  212. About.Open:
  213. Sub Open()
  214.   self.Title = "About " + Fin.AppName
  215.   NameStr.Text = Fin.AppName + Fin.SPACE + Fin.AppVersion
  216. End Sub
  217.  
  218. About.OKButton.Action:
  219. Sub Action()
  220.   About.Hide
  221. End Sub
  222.  
  223. Pic.SaveFile:
  224. Sub SaveFile(ask as boolean)
  225.   if ExportPicture(Image_p) then
  226.     CheckChanged.Value = false
  227.   end
  228. End Sub
  229.  
  230. Pic.setInfo:
  231. Sub setInfo()
  232.   WInfo.setSize(image_p.width, image_p.height, image_p.HorizontalResolution)
  233. End Sub
  234.  
  235. Pic.PicChange:
  236. Sub PicChange(winchanged as boolean)
  237.   dim scale, s as integer
  238.   dim targeth, targetw as integer
  239.   
  240.   if image_p = Nil then
  241.     return
  242.   end
  243.   scale = ViewScales(ViewScalePopup.ListIndex)
  244.   
  245.   if scale = -1 then
  246.     ' fit width
  247.     if Can.width < 20 then
  248.       scale = 20 * 100 / image_p.width
  249.     else
  250.       scale = Can.width * 100 / image_p.width
  251.     end
  252.   elseif scale = -2 then
  253.     'fit height
  254.     if Can.height < 20 then
  255.       scale = 20 * 100 / image_p.height
  256.     else
  257.       scale = Can.height * 100 / image_p.height
  258.     end
  259.   elseif scale = -3 then
  260.     ' fit both
  261.     if Can.width < 20 then
  262.       scale = 20 * 100 / image_p.width
  263.     else
  264.       scale = Can.width * 100 / image_p.width
  265.     end
  266.     if Can.height < 20 then
  267.       s = 20 * 100 / image_p.height
  268.     else
  269.       s = Can.height * 100 / image_p.height
  270.     end
  271.     if s < scale then
  272.       scale = s
  273.     end
  274.   elseif scale = -3 then
  275.     ' fit screen
  276.     scale = Screen(0).width * 100 / image_p.width
  277.     s = Screen(0).height * 100 / image_p.height
  278.     if s < scale then
  279.       scale = s
  280.     end
  281.   end
  282.   
  283.   targetw = image_p.width * scale / 100
  284.   targeth = image_p.height * scale / 100
  285.   
  286.   scroll_x = 0
  287.   scroll_y = 0
  288.   ScrollH.Value = 0
  289.   ScrollV.Value = 0
  290.   if Can.width > targetw then
  291.     ScrollH.Visible = false
  292.   else
  293.     ScrollH.Visible = true
  294.     ScrollH.Maximum = targetw - Can.width
  295.     ScrollH.PageStep = Can.width
  296.   end
  297.   if Can.height > targeth then
  298.     ScrollV.Visible = false
  299.   else
  300.     ScrollV.Visible = true
  301.     ScrollV.Maximum = targeth - Can.height
  302.     ScrollV.PageStep = Can.height
  303.   end
  304.   
  305.   display_p = NewPicture(targetw, targeth, 32)
  306.   if display_p = Nil then
  307.     MsgBox "Not enough memory to allocate working buffer"
  308.   else
  309.     display_p.graphics.drawPicture image_p, 0, 0, targetw, targeth, 0, 0, image_p.width, image_p.height
  310.   end
  311.   Can.Refresh
  312. End Sub
  313.  
  314. Pic.SizeChanged:
  315. Sub SizeChanged()
  316.   Can.width = me.width - ScrollV.width
  317.   Can.height = me.height - Can.Top - ScrollH.Height
  318.   PicChange(true)
  319.   ScrollV.Left = me.width - ScrollV.width
  320.   ScrollV.Height = me.height - Can.Top - ScrollH.height
  321.   ScrollH.Top = me.height - ScrollH.height
  322.   ScrollH.Width = me.width - ScrollV.width
  323. End Sub
  324.  
  325. Pic.setPic:
  326. Sub setPic(f as folderitem, pi as Picture)
  327.   image_p = pi
  328.   undo_p = pi
  329.   scroll_x = 0
  330.   scroll_y = 0
  331.   
  332.   display_p = Nil
  333.   PicChange(true)
  334.   
  335.   Pic.width = display_p.width + ScrollV.width
  336.   Pic.height = display_p.height + ScrollH.height + Can.Top
  337.   SizeChanged
  338.   
  339.   if f <> Nil then
  340.     me.Title = f.Name
  341.   else
  342.     me.Title = "Untitled"
  343.   end
  344.   me.show
  345.   CheckChanged.Value = false
  346.   setInfo
  347. End Sub
  348.  
  349. Pic.setWindow:
  350. Sub setWindow(x as integer, y as integer)
  351.   me.Left = x
  352.   me.Top = y
  353. End Sub
  354.  
  355. Pic.OpStart:
  356. Sub OpStart(op as string)
  357.   undo_p = image_p
  358.   EditUndo.Text = "Undo " + op
  359. End Sub
  360.  
  361. Pic.OpEnd:
  362. Sub OpEnd()
  363.   CheckChanged.Value = true
  364.   PicChange(false)
  365.   WInfo.setSize(image_p.width, image_p.height, image_p.HorizontalResolution)
  366. End Sub
  367.  
  368. Pic.Draw:
  369. Sub Draw(ps as printersetup, g as Graphics)
  370.   Fin.ImageSizer(image_p.Width, image_p.Height, Fin.PrinterWidth, Fin.PrinterHeight)
  371.   'MsgBox "i_pW=" + str(image_p.Width) + ", i_pH=" + str(image_p.Height) + ", pW=" + str(Fin.PrinterWidth) + ", pH=" + stR(Fin.PrinterHeight) + Fin.NL + "IL=" + str(Fin.ImageLeft) + ", IT=" + str(Fin.ImageTop) + ", IW=" + str(Fin.ImageWidth) + ", IH=" + stR(Fin.ImageHeight)
  372.   g.drawPicture image_p, Fin.ImageLeft, Fin.ImageTop, Fin.ImageWidth,  Fin.ImageHeight, 0, 0, image_p.Width, image_p.Height
  373. End Sub
  374.  
  375. Pic.Close:
  376. Sub Close()
  377.   App.WindowClose(self)
  378. End Sub
  379.  
  380. Pic.Resized:
  381. Sub Resized()
  382.   SizeChanged
  383. End Sub
  384.  
  385. Pic.MouseMove:
  386. Sub MouseMove(X As Integer, Y As Integer)
  387.   if App.w.getFront = winid then
  388.     WInfo.setXY(x, y)
  389.   end
  390. End Sub
  391.  
  392. Pic.Activate:
  393. Sub Activate()
  394.   App.w.setFront(winid)
  395.   if image_p <> Nil then
  396.     setInfo
  397.   end
  398. End Sub
  399.  
  400. Pic.CancelClose:
  401. Function CancelClose(appQuitting as Boolean) As Boolean
  402.   if CheckChanged.Value then
  403.     Fin.WindowCenter(SaveChanges)
  404.     #if TargetCarbon then
  405.       SaveChanges.ShowModalWithin(self)
  406.     #else
  407.       SaveChanges.ShowModal
  408.     #endif
  409.     if SaveChanges.pressed = "Save" then
  410.       SaveFile(false)
  411.     elseif SaveChanges.pressed = "Cancel" then
  412.       return true
  413.     end
  414.     SaveChanges.Close
  415.   end
  416.   return false
  417. End Function
  418.  
  419. Pic.EnableMenuItems:
  420. Sub EnableMenuItems()
  421.   if CheckChanged.Value then
  422.     FileSave.Enable
  423.   end
  424.   FileSaveAs.Enable
  425.   FileClose.Enable
  426.   if undo_p <> Nil then
  427.     EditUndo.Enable
  428.   else
  429.     EditUndo.Text = "Can't Undo"
  430.   end
  431.   EditCopy.Enable
  432.   EditInvert.Enable
  433.   EditPaste.Enable
  434.   EditImageSize.Enable
  435.   EditCanvasSize.Enable
  436.   EditRotateCW.Enable
  437.   EditRotateCCW.Enable
  438.   EditRotate180.Enable
  439.   EditMirrorHoriz.Enable
  440.   EditMirrorVert.Enable
  441.   EditSettoFillColor.Enable
  442.   EditInvert.Enable
  443.   EditConverttoWebColors.Enable
  444.   EditConverttoGrayscale.Enable
  445. End Sub
  446.  
  447. Pic.Open:
  448. Sub Open()
  449.   image_p = Nil
  450.   undo_p = Nil
  451.   
  452.   winid = App.w.getWinId
  453.   
  454.   ViewScalePopup.addRow "10%"
  455.   ViewScales(0) = 10
  456.   ViewScalePopup.addRow "25%"
  457.   ViewScales(1) = 25
  458.   ViewScalePopup.addRow "33%"
  459.   ViewScales(2) = 33
  460.   ViewScalePopup.addRow "50%"
  461.   ViewScales(3) = 50
  462.   ViewScalePopup.addRow "75%"
  463.   ViewScales(4) = 75
  464.   ViewScalePopup.addRow "100%"
  465.   ViewScales(5) = 100
  466.   ViewScalePopup.addRow "125%"
  467.   ViewScales(6) = 125
  468.   ViewScalePopup.addRow "150%"
  469.   ViewScales(7) = 150
  470.   ViewScalePopup.addRow "200%"
  471.   ViewScales(8) = 200
  472.   ViewScalePopup.addRow "300%"
  473.   ViewScales(9) = 300
  474.   ViewScalePopup.addRow "400%"
  475.   ViewScales(10) = 400
  476.   ViewScalePopup.addRow "1000%"
  477.   ViewScales(11) = 1000
  478.   ViewScalePopup.addRow "fit width"
  479.   ViewScales(12) = -1
  480.   ViewScalePopup.addRow "fit height"
  481.   ViewScales(13) = -2
  482.   ViewScalePopup.addRow "fit best"
  483.   ViewScales(14) = -3
  484.   ViewScalePopup.addRow "fit screen"
  485.   ViewScales(15) = -4
  486.   ViewScalePopup.ListIndex = 14
  487. End Sub
  488.  
  489. Pic.ViewScalePopup.Change:
  490. Sub Change()
  491.   PicChange(false)
  492. End Sub
  493.  
  494. Pic.Can.Paint:
  495. Sub Paint(g As Graphics)
  496.   if display_p <> Nil then
  497.     g.drawPicture display_p, 0, 0, g.width, g.height, scroll_x, scroll_y, g.width, g.height
  498.   end
  499. End Sub
  500.  
  501. Pic.ScrollV.ValueChanged:
  502. Sub ValueChanged()
  503.   scroll_y = me.Value
  504.   Can.Refresh
  505. End Sub
  506.  
  507. Pic.ScrollH.ValueChanged:
  508. Sub ValueChanged()
  509.   scroll_x = me.Value
  510.   Can.Refresh
  511. End Sub
  512.  
  513. WColor.DoIt:
  514. Sub DoIt()
  515.   dim x, y, ix as Integer
  516.   dim r, g, b as integer
  517.   dim i, j, k as Double
  518.   dim s as String
  519.   dim c as Color
  520.   
  521.   if not WColor.Visible then
  522.     return
  523.   end
  524.   x = System.MouseX
  525.   y = System.MouseY
  526.   c = System.Pixel(x, y)
  527.   XY.Text = "(" + cstr(x) + "," + cstr(y) + ")"
  528.   
  529.   Rect.FillColor = c
  530.   
  531.   r = c.Red
  532.   g = c.Green
  533.   b = c.Blue
  534.   RGBD.Text = "RGB " + Str(r) + "," + Str(g) + "," + Str(b)
  535.   
  536.   RGBH.Text = Fin.Hex2(r) + "," + Fin.Hex2(g) + "," + Fin.Hex2(b)
  537.   
  538.   i = c.Hue
  539.   j = c.Saturation
  540.   k = c.Value
  541.   xIHS.Text = "HSV " + cstr(Fin.R3(i)) + "," + cstr(Fin.R3(j)) + "," + cstr(Fin.R3(k))
  542.   
  543.   i = c.Cyan
  544.   j = c.Magenta
  545.   k = c.Yellow
  546.   xCMY.Text = "CMY " + cstr(Fin.R3(i)) + "," + cstr(Fin.R3(j)) + "," + cstr(Fin.R3(k))
  547.   
  548.   c = App.FC.GetWebColor(c)
  549.   r = c.Red
  550.   g = c.Green
  551.   b = c.Blue
  552.   WebSafe.Text = "Web Safe #" + Fin.Hex2(r) + Fin.Hex2(g) + Fin.Hex2(b)
  553.   ix = App.FC.GetIndex(c)
  554.   WebIndex.Text = "Web Index " + str(ix)
  555.   WebName.Text = "Web Name " + App.FC.GetName(ix)
  556. End Sub
  557.  
  558. WColor.Draw:
  559. Sub Draw(ps as printersetup, g as Graphics)
  560.   dim x, y, ix as Integer
  561.   dim r, gr, b as integer
  562.   dim i, j, k as Double
  563.   dim c, wc as Color
  564.   dim yy, size as integer
  565.   
  566.   yy = Fin.PrinterTop + g.TextHeight * Fin.PrinterScale
  567.   size = g.TextSize * Fin.PrinterScale
  568.   
  569.   x = System.MouseX
  570.   y = System.MouseY
  571.   c = System.Pixel(x, y)
  572.   g.drawString "(" + cstr(x) + "," + cstr(y) + ")", Fin.PrinterLeft, yy
  573.   yy = yy + size
  574.   
  575.   r = c.Red
  576.   gr = c.Green
  577.   b = c.Blue
  578.   g.DrawString "RGB " + Str(r) + "," + Str(gr) + "," + Str(b), Fin.PrinterLeft, yy
  579.   yy = yy + size
  580.   
  581.   g.drawString "RGB(hex) " + Fin.Hex2(r) + "," + Fin.Hex2(gr) + "," + Fin.Hex2(b), Fin.PrinterLeft, yy
  582.   yy = yy + size
  583.   
  584.   i = c.Hue
  585.   j = c.Saturation
  586.   k = c.Value
  587.   g.drawString "HSV " + cstr(Fin.R3(i)) + "," + cstr(Fin.R3(j)) + "," + cstr(Fin.R3(k)), Fin.PrinterLeft, yy
  588.   yy = yy + size
  589.   
  590.   i = c.Cyan
  591.   j = c.Magenta
  592.   k = c.Yellow
  593.   g.drawString "CMY " + cstr(Fin.R3(i)) + "," + cstr(Fin.R3(j)) + "," + cstr(Fin.R3(k)), Fin.PrinterLeft, yy
  594.   yy = yy + size
  595.   
  596.   wc = App.FC.GetWebColor(c)
  597.   r = wc.Red
  598.   gr = wc.Green
  599.   b = wc.Blue
  600.   g.drawString "Web Safe #" + Fin.Hex2(r) + Fin.Hex2(gr) + Fin.Hex2(b), Fin.PrinterLeft, yy
  601.   yy = yy + size
  602.   
  603.   ix = App.FC.GetIndex(wc)
  604.   g.drawString "Web Index " + str(ix), Fin.PrinterLeft, yy
  605.   yy = yy + size
  606.   
  607.   g.drawString "Web Safe #" + "Web Name " + App.FC.GetName(ix), Fin.PrinterLeft, yy
  608.   yy = yy + size
  609.   
  610.   g.ForeColor = c
  611.   g.fillRect Fin.PrinterLeft, yy, ps.HorizontalResolution, ps.VerticalResolution
  612. End Sub
  613.  
  614. WColor.LoadPrefs:
  615. Sub LoadPrefs()
  616.   dim i as Integer
  617.   dim b as Boolean
  618.   
  619.   if Pool.GetI("Color.Left", i) then
  620.     self.Left = i
  621.   end
  622.   
  623.   if Pool.GetI("Color.Top", i) then
  624.     self.Top = i
  625.   end
  626.   
  627.   Fin.WindowSane(self)
  628.   
  629.   if Pool.GetB("Color.Checked", b) then
  630.     if b then
  631.       InfoColor.Checked = true
  632.       self.Show
  633.     end
  634.   end
  635.   
  636.   Pool.SetI("Color.Left", self.Left)
  637.   Pool.SetI("Color.Top", self.Top)
  638.   Pool.SetB("Color.Checked", InfoColor.Checked)
  639. End Sub
  640.  
  641. WColor.CancelClose:
  642. Function CancelClose(appQuitting as Boolean) As Boolean
  643.   App.isquitting = true
  644. End Function
  645.  
  646. WColor.Close:
  647. Sub Close()
  648.   InfoColor.Checked = false
  649.   if not App.isquitting then Pool.SetB("Color.Checked", InfoColor.Checked)
  650. End Sub
  651.  
  652. WColor.Activate:
  653. Sub Activate()
  654.   App.w.setFront(winid)
  655. End Sub
  656.  
  657. WColor.Moved:
  658. Sub Moved()
  659.   Pool.SetI("Color.Left", self.Left)
  660.   Pool.SetI("Color.Top", self.Top)
  661. End Sub
  662.  
  663. WColor.Open:
  664. Sub Open()
  665.   if App.w = Nil then
  666.     App.w = new WindowList
  667.     if App.w = Nil then
  668.       MsgBox "Can't create WindowList"
  669.       Quit
  670.     end
  671.     App.w.init
  672.   end
  673.   winid = App.w.getWinId
  674. End Sub
  675.  
  676. WColor.Timer1.Action:
  677. Sub Action()
  678.   DoIt
  679. End Sub
  680.  
  681. WMagnify.setMag:
  682. Sub setMag(m as Integer)
  683.   mag = m
  684.   if mag = 2 then
  685.     But2.Value = true
  686.     Pool.SetS("Magnify.Mag", "2x")
  687.   elseif mag = 4 then
  688.     But4.Value = true
  689.     Pool.SetS("Magnify.Mag", "4x")
  690.   else
  691.     But8.Value = true
  692.     mag = 8
  693.     Pool.SetS("Magnify.Mag", "8x")
  694.   end
  695. End Sub
  696.  
  697. WMagnify.getMag:
  698. Function getMag() As Integer
  699.   return mag
  700. End Function
  701.  
  702. WMagnify.DoIt:
  703. Sub DoIt()
  704.   dim g as Graphics
  705.   dim e, i, j, ex, ey as Integer
  706.   dim x, y as integer
  707.   
  708.   if not WMagnify.Visible then
  709.     return
  710.   end
  711.   
  712.   x = System.MouseX
  713.   y = System.MouseY
  714.   g = Area.Graphics
  715.   e = g.width / mag
  716.   ex = x - e / 2
  717.   ey = y - e / 2
  718.   for i = 0 to e
  719.     for j = 0 to e
  720.       g.ForeColor = System.Pixel(ex + i, ey + j)
  721.       g.FillRect i * mag, j * mag, mag, mag
  722.     next
  723.   next
  724. End Sub
  725.  
  726. WMagnify.Draw:
  727. Sub Draw(ps as printersetup, g as Graphics)
  728.   dim e, i, j, ex, ey as Integer
  729.   dim x, y as integer
  730.   x = System.MouseX
  731.   y = System.MouseY
  732.   e = Area.Graphics.width / mag
  733.   ex = x - e / 2
  734.   ey = y - e / 2
  735.   for i = 0 to e
  736.     for j = 0 to e
  737.       g.ForeColor = System.Pixel(ex + i, ey + j)
  738.       g.FillRect Fin.PrinterLeft + i * mag, Fin.PrinterTop + j * mag, mag, mag
  739.     next
  740.   next
  741. End Sub
  742.  
  743. WMagnify.LoadPrefs:
  744. Sub LoadPrefs()
  745.   dim i as Integer
  746.   dim b as Boolean
  747.   dim s as String
  748.   
  749.   if Pool.GetI("Magnify.Left", i) then
  750.     self.Left = i
  751.   end
  752.   
  753.   if Pool.GetI("Magnify.Top", i) then
  754.     self.Top = i
  755.   end
  756.   
  757.   Fin.WindowSane(self)
  758.   
  759.   if Pool.GetB("Magnify.Checked", b) then
  760.     if b then
  761.       InfoMagnify.Checked = true
  762.       self.Show
  763.     else
  764.       InfoMagnify.Checked = false
  765.       self.Hide
  766.     end
  767.   end
  768.   
  769.   if Pool.GetS("Magnify.Mag", s) then
  770.     if s = "2x" then
  771.       But2.Value = true
  772.     elseif s = "4x" then
  773.       But4.Value = true
  774.     else
  775.       But8.Value = true
  776.     end
  777.   end
  778.   
  779.   Pool.SetI("Magnify.Left", self.Left)
  780.   Pool.SetI("Magnify.Top", self.Top)
  781.   Pool.SetB("Magnify.Checked", InfoMagnify.Checked)
  782.   
  783.   if But2.Value then
  784.     s = "2x"
  785.   elseif But4.Value then
  786.     s = "4x"
  787.   else
  788.     s = "8x"
  789.   end
  790.   Pool.SetS("Magnify.Mag", s)
  791. End Sub
  792.  
  793. WMagnify.CancelClose:
  794. Function CancelClose(appQuitting as Boolean) As Boolean
  795.   App.isquitting = true
  796. End Function
  797.  
  798. WMagnify.Moved:
  799. Sub Moved()
  800.   Pool.SetI("Magnify.Left", self.Left)
  801.   Pool.SetI("Magnify.Top", self.Top)
  802. End Sub
  803.  
  804. WMagnify.Close:
  805. Sub Close()
  806.   InfoMagnify.Checked = false
  807.   if not App.isquitting then Pool.SetB("Magnify.Checked", InfoMagnify.Checked)
  808. End Sub
  809.  
  810. WMagnify.Activate:
  811. Sub Activate()
  812.   App.w.setFront(winid)
  813. End Sub
  814.  
  815. WMagnify.Open:
  816. Sub Open()
  817.   setMag(8)
  818.   if App.w = Nil then
  819.     App.w = new WindowList
  820.     if App.w = Nil then
  821.       MsgBox "Can't create WindowList"
  822.       Quit
  823.     end
  824.     App.w.init
  825.   end
  826.   winid = App.w.getWinId
  827. End Sub
  828.  
  829. WMagnify.But2.Action:
  830. Sub Action()
  831.   setMag(2)
  832. End Sub
  833.  
  834. WMagnify.But4.Action:
  835. Sub Action()
  836.   setMag(4)
  837. End Sub
  838.  
  839. WMagnify.But8.Action:
  840. Sub Action()
  841.   setMag(8)
  842. End Sub
  843.  
  844. WMagnify.Timer1.Action:
  845. Sub Action()
  846.   DoIt
  847. End Sub
  848.  
  849. FileColors.DoLine:
  850. Sub DoLine(cnt as integer, s as string)
  851.   dim ss as String = s
  852.   dim colr as String
  853.   dim cname as String
  854.   
  855.   'skip blank, short, or comment lines
  856.   if Len(ss) < 8 or Left(ss, 1) = "#" then
  857.     return
  858.   end
  859.   
  860.   colr = Fin.SplitOff(Fin.TAB, ss)
  861.   if colr = "" or Len(colr) <> 6 then
  862.     MsgBox "Missing Color on line " + str(cnt)
  863.     return
  864.   end
  865.   
  866.   cname = ss
  867.   if cname = "" then
  868.     MsgBox "Missing Name on line " + str(cnt)
  869.     return
  870.   end
  871.   
  872.   dim c as Color = Fin.SToColor(colr)
  873.   dim i as Integer = App.FC.GetIndex(c)
  874.   Names(i) = cname
  875. End Sub
  876.  
  877. FileColors.GetIndex:
  878. Function GetIndex(c as Color) As integer
  879.   dim cc as Color
  880.   cc = GetWebColor(c)
  881.   return cc.Red / 51 * 36 + cc.Green / 51 * 6 + cc.Blue / 51
  882. End Function
  883.  
  884. FileColors.GetName:
  885. Function GetName(i as integer) As string
  886.   return Names(i)
  887. End Function
  888.  
  889. FileColors.GetWebColor:
  890. Function GetWebColor(c as Color) As Color
  891.   dim r, g, b as integer
  892.   r = (c.Red + 26) / 51
  893.   r = r * 51
  894.   g = (c.Green + 26) / 51
  895.   g = g * 51
  896.   b = (c.Blue + 26) / 51
  897.   b = b * 51
  898.   return RGB(r, g, b)
  899. End Function
  900.  
  901. FileColors.Load:
  902. Function Load(fn as string) As boolean
  903.   dim f as folderItem
  904.   dim i as integer
  905.   dim s as TextInputStream
  906.   
  907.   for i = 0 to 215
  908.     Names(i) = "-"
  909.   next
  910.   
  911.   f = GetFolderItem(fn)
  912.   if f = Nil or not f.Exists then
  913.     return true
  914.   end
  915.   
  916.   s = f.OpenAsTextFile
  917.   i = 1
  918.   while not s.EOF
  919.     DoLine(i, s.ReadLine)
  920.     i = i + 1
  921.   wend
  922.   s.Close
  923.   return true
  924. End Function
  925.  
  926. WInfo.setSize:
  927. Sub setSize(x as integer, y as integer, r as integer)
  928.   dim rr as double
  929.   rr = r
  930.   WidthP.Text = "w: " + cstr(x)
  931.   HeightP.Text = "h: " + cstr(y)
  932.   WidthD.Text = "w: " + cstr(x / rr) + " in"
  933.   HeightD.Text = "h: " + cstr(y / rr) + " in"
  934.   ResolutionD.Text = "res: " + cstr(r) + "/in"
  935.   Memory.Text = Fin.formatMemory(1.0 * x * y * 32 / 8)
  936. End Sub
  937.  
  938. WInfo.LoadPrefs:
  939. Sub LoadPrefs()
  940.   dim i as Integer
  941.   dim b as Boolean
  942.   dim c as Color
  943.   
  944.   if Pool.GetI("Info.Left", i) then
  945.     self.Left = i
  946.   end
  947.   
  948.   if Pool.GetI("Info.Top", i) then
  949.     self.Top = i
  950.   end
  951.   
  952.   Fin.WindowSane(self)
  953.   if Pool.GetB("Info.Checked", b) then
  954.     if b then
  955.       InfoInfo.Checked = true
  956.       self.Show
  957.     end
  958.   end
  959.   
  960.   if Pool.GetC("Info.Color", c) then
  961.     FillClr.FillColor = c
  962.   end
  963.   
  964.   Pool.SetI("Info.Left", self.Left)
  965.   Pool.SetI("Info.Top", self.Top)
  966.   Pool.SetB("Info.Checked", InfoInfo.Checked)
  967.   Pool.SetC("Info.Color", FillClr.FillColor)
  968. End Sub
  969.  
  970. WInfo.setXY:
  971. Sub setXY(x as integer, y as integer)
  972.   XP.Text = "x: " + cstr(x)
  973.   YP.Text = "y: " + cstr(y)
  974. End Sub
  975.  
  976. WInfo.setFillColor:
  977. Sub setFillColor(c as Color)
  978.   FillClr.FillColor = c
  979.   Pool.SetC("Info.Color", FillClr.FillColor)
  980. End Sub
  981.  
  982. WInfo.getFillColor:
  983. Function getFillColor() As Color
  984.   return FillClr.FillColor
  985. End Function
  986.  
  987. WInfo.Draw:
  988. Sub Draw(ps as printerSetup, g as graphics)
  989.   dim yy, size as integer
  990.   
  991.   yy = Fin.PrinterTop + g.TextHeight * Fin.PrinterScale
  992.   size = g.TextSize * Fin.PrinterScale
  993.   
  994.   g.drawString XP.Text, Fin.PrinterLeft, yy
  995.   yy = yy + size
  996.   
  997.   g.drawString YP.Text, Fin.PrinterLeft, yy
  998.   yy = yy + size
  999.   
  1000.   g.drawString WidthP.Text, Fin.PrinterLeft, yy
  1001.   yy = yy + size
  1002.   
  1003.   g.drawString HeightP.Text, Fin.PrinterLeft, yy
  1004.   yy = yy + size
  1005.   
  1006.   g.drawString WidthD.Text, Fin.PrinterLeft, yy
  1007.   yy = yy + size
  1008.   
  1009.   g.drawString HeightD.Text, Fin.PrinterLeft, yy
  1010.   yy = yy + size
  1011.   
  1012.   g.drawString ResolutionD.Text, Fin.PrinterLeft, yy
  1013.   yy = yy + size
  1014.   
  1015.   g.drawString Memory.Text, Fin.PrinterLeft, yy
  1016.   yy = yy + size
  1017.   
  1018.   g.drawString "fill color: (" + str(FillClr.FillColor.Red)  + "," + str(FillClr.FillColor.Green)  + "," + str(FillClr.FillColor.Blue)  + ")", Fin.PrinterLeft, yy
  1019. End Sub
  1020.  
  1021. WInfo.CancelClose:
  1022. Function CancelClose(appQuitting as Boolean) As Boolean
  1023.   App.isquitting = true
  1024. End Function
  1025.  
  1026. WInfo.Moved:
  1027. Sub Moved()
  1028.   Pool.SetI("Info.Left", self.Left)
  1029.   Pool.SetI("Info.Top", self.Top)
  1030. End Sub
  1031.  
  1032. WInfo.Activate:
  1033. Sub Activate()
  1034.   App.w.setFront(winid)
  1035. End Sub
  1036.  
  1037. WInfo.Close:
  1038. Sub Close()
  1039.   InfoInfo.Checked = false
  1040.   if not App.isquitting then Pool.SetB("Info.Checked", InfoInfo.Checked)
  1041. End Sub
  1042.  
  1043. WInfo.Open:
  1044. Sub Open()
  1045.   InfoInfo.Checked = false
  1046.   setXY(0, 0)
  1047.   setSize(1, 1, 72)
  1048.   setFillColor(RGB(0, 0, 0))
  1049.   
  1050.   if App.w = Nil then
  1051.     App.w = new WindowList
  1052.     if App.w = Nil then
  1053.       MsgBox "Can't create WindowList"
  1054.       Quit
  1055.     end
  1056.     App.w.init
  1057.   end
  1058.   winid = App.w.getWinId
  1059. End Sub
  1060.  
  1061. WInfo.FillClr.MouseDown:
  1062. Function MouseDown(X As Integer, Y As Integer) As Boolean
  1063.   Dim c as Color
  1064.   c = FillClr.FillColor
  1065.   if selectColor(c, "Select Fill Color") then
  1066.     FillClr.FillColor = c
  1067.   end
  1068. End Function
  1069.  
  1070. SaveChanges.ButCancel.Action:
  1071. Sub Action()
  1072.   pressed = "Cancel"
  1073.   hide
  1074. End Sub
  1075.  
  1076. SaveChanges.ButSave.Action:
  1077. Sub Action()
  1078.   pressed = "Save"
  1079.   hide
  1080. End Sub
  1081.  
  1082. SaveChanges.ButDont.Action:
  1083. Sub Action()
  1084.   pressed = "DontSave"
  1085.   hide
  1086. End Sub
  1087.  
  1088. SaveChanges.Canvas1.Paint:
  1089. Sub Paint(g As Graphics)
  1090.   g.drawCautionIcon 0, 0
  1091. End Sub
  1092.  
  1093. WindowList.setFront:
  1094. Sub setFront(x as integer)
  1095.   front = x
  1096. End Sub
  1097.  
  1098. WindowList.init:
  1099. Sub init()
  1100.   front = 0
  1101.   winid = 0
  1102. End Sub
  1103.  
  1104. WindowList.getFront:
  1105. Function getFront() As integer
  1106.   return front
  1107. End Function
  1108.  
  1109. WindowList.getWinId:
  1110. Function getWinId() As integer
  1111.   winid = winid + 1
  1112.   return winid
  1113. End Function
  1114.  
  1115. NewDialog.ButOK.Action:
  1116. Sub Action()
  1117.   pressed = "OK"
  1118.   hide
  1119. End Sub
  1120.  
  1121. NewDialog.ButCancel.Action:
  1122. Sub Action()
  1123.   pressed = "Cancel"
  1124.   hide
  1125. End Sub
  1126.  
  1127. PBThread.Start:
  1128. Function Start(range as integer) As integer
  1129.   ProgBar.PB.Value = 0
  1130.   Fin.WindowCenter(ProgBar)
  1131.   ProgBar.Show
  1132.   return range / 100
  1133. End Function
  1134.  
  1135. PBThread.Done:
  1136. Sub Done()
  1137.   ProgBar.Hide
  1138. End Sub
  1139.  
  1140. PBThread.Run:
  1141. Sub Run()
  1142.   ProgBar.PB.Value = App.pbvalue
  1143.   ProgBar.PB.Refresh
  1144. End Sub
  1145.  
  1146. SlideShow.go:
  1147. Sub go(f as folderItem)
  1148.   if f.directory then
  1149.     dir_f = f
  1150.   else
  1151.     dir_f = f.parent
  1152.   end
  1153.   if dir_f = Nil or not dir_f.directory then
  1154.     MsgBox "unable to access directory for " + f.Name
  1155.     return
  1156.   end
  1157.   if dir_f.count < 1 then
  1158.     MsgBox "no files"
  1159.     return
  1160.   end
  1161.   current = 1
  1162.   total = dir_f.count - 1
  1163.   pressed = ""
  1164.   starting = true
  1165.   #if TargetWin32 then
  1166.     SlideShow.Left = 10
  1167.     SlideShow.Top = 10
  1168.     SlideShow.Width = App.MDIWindow.Width - 20
  1169.     SlideShow.Height = App.MDIWindow.Height - 20
  1170.   #else
  1171.     SlideShow.Left = Screen(0).AvailableLeft
  1172.     SlideShow.Top = Screen(0).AvailableTop + App.window_topmargin
  1173.     SlideShow.Width = Screen(0).AvailableWidth - SlideShow.Left
  1174.     SlideShow.Height = Screen(0).AvailableHeight - SlideShow.Top
  1175.   #endif
  1176.   SlideShow.Can.Width = SlideShow.Width
  1177.   SlideShow.Can.Height = SlideShow.Height - SlideShow.Can.Top
  1178.   SlideShow.Show
  1179.   App.sst.Run
  1180. End Sub
  1181.  
  1182. SlideShow.doit:
  1183. Sub doit()
  1184.   if starting then
  1185.     starting = false
  1186.   else
  1187.     if pressed = "stop" then
  1188.       SlideShow.Hide
  1189.       return
  1190.     elseif pressed = "pause" then
  1191.       return
  1192.     elseif pressed = "first" then
  1193.       current = 1
  1194.     elseif pressed = "last" then
  1195.       current = total
  1196.     elseif pressed = "-10" then
  1197.       current = current - 10
  1198.       if current < 1 then
  1199.         current = 1
  1200.       end
  1201.     elseif pressed = "+10" then
  1202.       current = current + 10
  1203.       if current > total then
  1204.         current = total
  1205.       end
  1206.     else
  1207.       if RadBackward.Value then
  1208.         current = current - 1
  1209.       else
  1210.         current = current + 1
  1211.       end
  1212.     end
  1213.     pressed = ""
  1214.     if current < 1 or current > total then
  1215.       SlideShow.hide
  1216.     end
  1217.     App.sst.run
  1218.   end
  1219. End Sub
  1220.  
  1221. SlideShow.ButFirst.Action:
  1222. Sub Action()
  1223.   pressed = "first"
  1224.   doit
  1225. End Sub
  1226.  
  1227. SlideShow.ButM10.Action:
  1228. Sub Action()
  1229.   pressed = "-10"
  1230.   doit
  1231. End Sub
  1232.  
  1233. SlideShow.ButPause.Action:
  1234. Sub Action()
  1235.   if ButPause.Caption = "Pause" then
  1236.     ButPause.Caption = "Play"
  1237.     pressed = "pause"
  1238.   else
  1239.     ButPause.Caption = "Pause"
  1240.     pressed = ""
  1241.   end
  1242. End Sub
  1243.  
  1244. SlideShow.ButP10.Action:
  1245. Sub Action()
  1246.   pressed = "+10"
  1247.   doit
  1248. End Sub
  1249.  
  1250. SlideShow.ButLast.Action:
  1251. Sub Action()
  1252.   pressed = "last"
  1253.   doit
  1254. End Sub
  1255.  
  1256. SlideShow.ButStop.Action:
  1257. Sub Action()
  1258.   pressed = "stop"
  1259.   doit
  1260. End Sub
  1261.  
  1262. SlideShow.Timer1.Action:
  1263. Sub Action()
  1264.   doit
  1265. End Sub
  1266.  
  1267. ImageSize.button:
  1268. Sub button(s as double)
  1269.   EditWidth.Text = cstr(floor(App.image_width * s))
  1270.   EditWidth.SelStart = 0
  1271.   EditWidth.SelLength = len(EditWidth.Text)
  1272.   EditHeight.Text = cstr(floor(App.image_height * s))
  1273.   EditHeight.SelStart = 0
  1274.   EditHeight.SelLength = len(EditHeight.Text)
  1275. End Sub
  1276.  
  1277. ImageSize.Open:
  1278. Sub Open()
  1279.   updating = ""
  1280. End Sub
  1281.  
  1282. ImageSize.But4x.Action:
  1283. Sub Action()
  1284.   button(4)
  1285. End Sub
  1286.  
  1287. ImageSize.But3x.Action:
  1288. Sub Action()
  1289.   button(3)
  1290. End Sub
  1291.  
  1292. ImageSize.But2x.Action:
  1293. Sub Action()
  1294.   button(2)
  1295. End Sub
  1296.  
  1297. ImageSize.But15x.Action:
  1298. Sub Action()
  1299.   button(1.5)
  1300. End Sub
  1301.  
  1302. ImageSize.ButD15.Action:
  1303. Sub Action()
  1304.   button(1 / 1.5)
  1305. End Sub
  1306.  
  1307. ImageSize.ButD2.Action:
  1308. Sub Action()
  1309.   button(1/2)
  1310. End Sub
  1311.  
  1312. ImageSize.ButD3.Action:
  1313. Sub Action()
  1314.   button(1/3)
  1315. End Sub
  1316.  
  1317. ImageSize.ButD4.Action:
  1318. Sub Action()
  1319.   button(1/4)
  1320. End Sub
  1321.  
  1322. ImageSize.EditWidth.TextChange:
  1323. Sub TextChange()
  1324.   if CheckKeep.Value and updating <> "h" then
  1325.     updating = "w"
  1326.     EditHeight.Text = cstr(floor(1.0 * App.image_height / App.image_width * cdbl(EditWidth.Text)))
  1327.     EditHeight.SelStart = 0
  1328.     EditHeight.SelLength = len(EditHeight.Text)
  1329.     updating = ""
  1330.   end
  1331. End Sub
  1332.  
  1333. ImageSize.EditHeight.TextChange:
  1334. Sub TextChange()
  1335.   if CheckKeep.Value and updating <> "w" then
  1336.     updating = "h"
  1337.     EditWidth.Text = cstr(floor(1.0 * App.image_width / App.image_height * cdbl(EditHeight.Text)))
  1338.     EditWidth.SelStart = 0
  1339.     EditWidth.SelLength = len(EditWidth.Text)
  1340.     updating = ""
  1341.   end
  1342. End Sub
  1343.  
  1344. ImageSize.ButOK.Action:
  1345. Sub Action()
  1346.   pressed = "ok"
  1347.   App.image_width = cdbl(EditWidth.Text)
  1348.   if App.image_width < 1 then
  1349.     App.image_width = 1
  1350.   end
  1351.   App.image_height = cdbl(EditHeight.Text)
  1352.   if App.image_height < 1 then
  1353.     App.image_height = 1
  1354.   end
  1355.   hide
  1356. End Sub
  1357.  
  1358. ImageSize.ButCancel.Action:
  1359. Sub Action()
  1360.   pressed = "cancel"
  1361.   hide
  1362. End Sub
  1363.  
  1364. CanvasSize.ButCancel.Action:
  1365. Sub Action()
  1366.   pressed = "cancel"
  1367.   hide
  1368. End Sub
  1369.  
  1370. CanvasSize.ButOK.Action:
  1371. Sub Action()
  1372.   pressed = "ok"
  1373.   App.image_width = cdbl(EditWidth.Text)
  1374.   if App.image_width < 1 then
  1375.     App.image_width = 1
  1376.   end
  1377.   App.image_height = cdbl(EditHeight.Text)
  1378.   if App.image_height < 1 then
  1379.     App.image_height = 1
  1380.   end
  1381.   hide
  1382. End Sub
  1383.  
  1384. CanvasSize.Fill.MouseDown:
  1385. Function MouseDown(X As Integer, Y As Integer) As Boolean
  1386.   Dim c as Color
  1387.   c = Winfo.FillClr.FillColor
  1388.   if selectColor(c, "Select Fill Color") then
  1389.     WInfo.FillClr.FillColor = c
  1390.     Fill.FillColor = c
  1391.   end
  1392. End Function
  1393.  
  1394. SSThread.Run:
  1395. Sub Run()
  1396.   Dim p as Picture
  1397.   dim w, h as integer
  1398.   dim scale, s as double
  1399.   
  1400.   if SlideShow.dir_f.item(SlideShow.current) <> Nil then
  1401.     
  1402.     SlideShow.Count.Text = cstr(SlideShow.current) + "/" + cstr(SlideShow.total)
  1403.     SlideShow.FileName.Text = SlideShow.dir_f.item(SlideShow.current).AbsolutePath
  1404.     
  1405.     SlideShow.Can.graphics.foreColor = RGB(0, 0, 0)
  1406.     SlideShow.Can.graphics.fillRect 0, 0, SlideShow.Can.width, SlideShow.Can.height
  1407.     p = SlideShow.dir_f.item(SlideShow.current).OpenAsPicture
  1408.     if p <> Nil then
  1409.       ' fit both
  1410.       scale = SlideShow.Can.width / p.width
  1411.       w = SlideShow.Can.width
  1412.       h = p.height * scale
  1413.       s = SlideShow.Can.height / p.height
  1414.       if s < scale then
  1415.         w = p.width * s
  1416.         h = SlideShow.Can.height
  1417.       end
  1418.       SlideShow.Can.graphics.drawPicture p, 0, 0, w, h, 0, 0, p.width, p.height
  1419.     else
  1420.       SlideShow.Can.graphics.foreColor = RGB(255, 255, 255)
  1421.       SlideShow.Can.graphics.drawString "Not a graphics file", 50, 50
  1422.     end
  1423.   end
  1424. End Sub
  1425.  
  1426. FinUpdate.PhaseOne:
  1427. Protected Sub PhaseOne()
  1428.   Message.Text = "Check for Updates?"
  1429.   ButCancel.Visible = true
  1430.   ButOK.Visible = true
  1431.   PBar.Visible = false
  1432.   phase = "one"
  1433. End Sub
  1434.  
  1435. FinUpdate.PhaseTwo:
  1436. Protected Sub PhaseTwo()
  1437.   Message.Text = "Checking..."
  1438.   PBar.Visible = true
  1439.   phase = "two"
  1440.   HP.Get(Fin.VersionURL)
  1441. End Sub
  1442.  
  1443. FinUpdate.PhaseThree:
  1444. Protected Sub PhaseThree(content as String)
  1445.   if Len(content) < 10 then
  1446.     NotFound
  1447.     return
  1448.   end
  1449.   
  1450.   dim a(-1) as String = Split(content, "<release>")
  1451.   if UBound(a) < 1 then
  1452.     NotFound
  1453.     return
  1454.   end
  1455.   
  1456.   dim i as Integer
  1457.   dim lookfor as String = "<program>" + Fin.AppName + "</program>"
  1458.   for i = 0 to UBound(a) - 1
  1459.     if InStr(a(i), lookfor) > 0 and Found(a(i)) then return
  1460.   next
  1461.   NotFound
  1462. End Sub
  1463.  
  1464. FinUpdate.NotFound:
  1465. Protected Sub NotFound()
  1466.   Message.Text = "No newer version found."
  1467.   PBar.Visible = false
  1468.   ButOK.Visible = true
  1469.   ButCancel.Visible = false
  1470. End Sub
  1471.  
  1472. FinUpdate.Found:
  1473. Protected Function Found(s as String) As Boolean
  1474.   ' found possible release, return true if OK or false if we should keep looking
  1475.   
  1476.   'MsgBox "Found: " + s
  1477.   
  1478.   dim lookfor as String = "<target>" + Fin.TargetSystem + "</target>"
  1479.   if InStr(s, lookfor) <=  0 then return false
  1480.   'MsgBox "Matched TargetSystem of " + Fin.TargetSystem
  1481.   
  1482.   dim i as Integer = InStr(s, "<version>")
  1483.   dim j as Integer = InStr(s, "</version>")
  1484.   if i <= 0 or j <= 0 then return false
  1485.   rVersion = Mid(s, i + 9, j - i - 9)
  1486.   'MsgBox "Found version of " + rVersion
  1487.   if rVersion <= Fin.AppVersion then return false
  1488.   
  1489.   i = InStr(s, "<date>")
  1490.   j = InStr(s, "</date>")
  1491.   if i <= 0 or j <= 0 then return false
  1492.   rDate = Mid(s, i + 6, j - i - 6)
  1493.   'MsgBox "Found date of " + rDate
  1494.   
  1495.   i = InStr(s, "<size>")
  1496.   j = InStr(s, "</size>")
  1497.   if i <= 0 or j <= 0 then return false
  1498.   rSize = Mid(s, i + 6, j - i - 6)
  1499.   'MsgBox "Found size of " + rSize
  1500.   
  1501.   i = InStr(s, "<url>")
  1502.   j = InStr(s, "</url>")
  1503.   if i <= 0 or j <= 0 then return false
  1504.   rURL = Mid(s, i + 5, j - i - 5)
  1505.   'MsgBox "Found URL of " + rURL
  1506.   
  1507.   phase = "four"
  1508.   return true
  1509. End Function
  1510.  
  1511. FinUpdate.PhaseFour:
  1512. Protected Sub PhaseFour()
  1513.   Message.Text = "A new version is available" + Fin.NL + Fin.NL
  1514.   Message.Text = Message.Text + "The new version is " + rVersion
  1515.   Message.Text = Message.Text + ", it was released on " + rDate
  1516.   Message.Text = Message.Text + ", and it is " + Fin.formatMemoryNice(val(rSize))
  1517.   Message.Text = Message.Text + ".  Do you want to load it (with your web browser)?"
  1518.   PBar.Visible = false
  1519.   ButCancel.Visible = true
  1520.   ButOK.Visible = true
  1521.   phase = "five"
  1522. End Sub
  1523.  
  1524. FinUpdate.Open:
  1525. Sub Open()
  1526.   phase = ""
  1527. End Sub
  1528.  
  1529. FinUpdate.Activate:
  1530. Sub Activate()
  1531.   if phase = "" then
  1532.     PhaseOne
  1533.   end
  1534. End Sub
  1535.  
  1536. FinUpdate.ButCancel.Action:
  1537. Sub Action()
  1538.   phase = ""
  1539.   self.Hide
  1540. End Sub
  1541.  
  1542. FinUpdate.ButOK.Action:
  1543. Sub Action()
  1544.   if phase = "one" then
  1545.     PhaseTwo
  1546.   elseif phase = "five" then
  1547.     ShowURL(rURL)
  1548.     phase = ""
  1549.     self.Hide
  1550.   else
  1551.     phase = ""
  1552.     self.Hide
  1553.   end
  1554. End Sub
  1555.  
  1556. FinUpdate.HP.PageReceived:
  1557. Sub PageReceived(url as string, httpStatus as integer, headers as internetHeaders, content as string)
  1558.   PhaseThree(content)
  1559.   if phase = "four" then PhaseFour
  1560. End Sub
  1561.  
  1562. FinUpdate.HP.Error:
  1563. Sub Error(code as integer)
  1564.   Message.Text = "There was a communications error with the web site.  Please try again later.  (Code: " + str(code) + ")"
  1565.   PBar.Visible = false
  1566.   ButOK.Visible = false
  1567.   phase = ""
  1568. End Sub
  1569.  
  1570. Pool.SetS:
  1571. Protected Sub SetS(n as String, s as String)
  1572.   ' save s under name n
  1573.   if p <> nil then p.Value(n) = s
  1574.   if b <> nil then b.Value(n) = 0
  1575. End Sub
  1576.  
  1577. Pool.SetB:
  1578. Protected Sub SetB(n as String, b as Boolean)
  1579.   ' save b under name n
  1580.   if p <> nil then p.Value(n) = b
  1581. End Sub
  1582.  
  1583. Pool.SetI:
  1584. Protected Sub SetI(n as String, i as Integer)
  1585.   ' save i under name n
  1586.   if p <> nil then p.Value(n) = i
  1587. End Sub
  1588.  
  1589. Pool.SetD:
  1590. Protected Sub SetD(n as String, d as Double)
  1591.   ' save d under name n
  1592.   if p <> nil then p.Value(n) = d
  1593. End Sub
  1594.  
  1595. Pool.SetBin:
  1596. Protected Sub SetBin(n as String, s as String)
  1597.   ' save s under name n
  1598.   if p <> nil then p.Value(n) = s
  1599.   if b <> nil then b.Value(n) = 1
  1600. End Sub
  1601.  
  1602. Pool.SetC:
  1603. Protected Sub SetC(n as String, c as Color)
  1604.   ' save c under name 
  1605.   if p <> nil then p.Value(n) = c
  1606. End Sub
  1607.  
  1608. Pool.SetF:
  1609. Protected Sub SetF(n as String, f as FolderItem)
  1610.   ' save f under name n
  1611.   if p <> nil then p.Value(n) = f
  1612. End Sub
  1613.  
  1614. Pool.GetB:
  1615. Protected Function GetB(n as String, byref b as Boolean) As Boolean
  1616.   ' if n exists, set b to its value and return true else return false
  1617.   Mark(n)
  1618.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kBoolean then
  1619.     b = p.Value(n)
  1620.     return true
  1621.   else
  1622.     return false
  1623.   end
  1624. End Function
  1625.  
  1626. Pool.GetBin:
  1627. Protected Function GetBin(n as String, byref s as String) As Boolean
  1628.   ' if n exists, set s to its value and return true else return false
  1629.   ' binaries are just like strings except that their Encoding is always 0
  1630.   ' and they are always stored using base64
  1631.   Mark(n)
  1632.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kString then
  1633.     s = p.Value(n)
  1634.     return true
  1635.   else
  1636.     return false
  1637.   end
  1638. End Function
  1639.  
  1640. Pool.GetC:
  1641. Protected Function GetC(n as String, byref c as Color) As Boolean
  1642.   ' if n exists, set d to its value and return true else return false
  1643.   Mark(n)
  1644.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kColor then
  1645.     c = p.Value(n)
  1646.     return true
  1647.   else
  1648.     return false
  1649.   end
  1650. End Function
  1651.  
  1652. Pool.GetD:
  1653. Protected Function GetD(n as String, byref d as Double) As Boolean
  1654.   ' if n exists, set d to its value and return true else return false
  1655.   Mark(n)
  1656.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kDouble then
  1657.     d = p.Value(n)
  1658.     return true
  1659.   else
  1660.     return false
  1661.   end
  1662. End Function
  1663.  
  1664. Pool.GetF:
  1665. Protected Function GetF(n as String, byref f as FolderItem) As Boolean
  1666.   ' if n exists, set f to its value and return true else return false
  1667.   Mark(n)
  1668.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kObject then
  1669.     f = p.Value(n)
  1670.     return true
  1671.   else
  1672.     return false
  1673.   end
  1674. End Function
  1675.  
  1676. Pool.GetI:
  1677. Protected Function GetI(n as String, byref i as Integer) As Boolean
  1678.   ' if n exists, set i to its value and return true else return false
  1679.   Mark(n)
  1680.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kInteger then
  1681.     i = p.Value(n)
  1682.     return true
  1683.   else
  1684.     return false
  1685.   end
  1686. End Function
  1687.  
  1688. Pool.GetS:
  1689. Protected Function GetS(n as String, byref s as String) As Boolean
  1690.   ' if n exists, set s to its value and return true else return false
  1691.   Mark(n)
  1692.   if p <> nil and p.HasKey(n) and p.Value(n).Type = kString then
  1693.     s = p.Value(n)
  1694.     return true
  1695.   else
  1696.     return false
  1697.   end
  1698. End Function
  1699.  
  1700. Pool.Mark:
  1701. Private Sub Mark(n as String)
  1702.   ' mark the name to be permanently saved
  1703.   if m <> nil then m.Value(n) = 1
  1704. End Sub
  1705.  
  1706. Pool.Init:
  1707. Protected Function Init(domain as String, program as String) As Boolean
  1708.   #if DebugOpen then
  1709.     MsgBox "Pool Init Start"
  1710.   #endif
  1711.   filename = domain + ".prefs." + program
  1712.   
  1713.   p = new Dictionary
  1714.   b = new Dictionary
  1715.   m = new Dictionary
  1716.   if p = nil or b = nil or m = nil then
  1717.     MsgBox "Unable to initialize preferences"
  1718.     return false
  1719.   end
  1720.   return Reload
  1721. End Function
  1722.  
  1723. Pool.Reload:
  1724. Protected Function Reload() As Boolean
  1725.   p.Clear     ' pool for holding values
  1726.   m.Clear     ' set to 1 if name is to be saved
  1727.   b.Clear     ' for strings, set to 1 for binary, 0 for string
  1728.   
  1729.   dim f as FolderItem
  1730.   dim fs as TextInputStream
  1731.   f = PreferencesFolder.child(filename)
  1732.   if f = nil then
  1733.     f = GetFolderItem(filename)
  1734.     if f = nil then
  1735.       MsgBox "Unable to locate file " + filename
  1736.       return false
  1737.     end
  1738.   end
  1739.   
  1740.   fs = f.OpenAsTextFile
  1741.   if fs = nil then return true     ' no previous file
  1742.   
  1743.   while not fs.EOF
  1744.     ReloadItem fs.ReadLine
  1745.   wend
  1746.   fs.Close
  1747.   return true
  1748. End Function
  1749.  
  1750. Pool.Save:
  1751. Protected Sub Save()
  1752.   dim f as FolderItem
  1753.   dim fs as TextOutputStream
  1754.   f = SaveGetFolder
  1755.   if f = nil then return
  1756.   
  1757.   fs = f.CreateTextFile
  1758.   if fs = Nil then
  1759.     MsgBox "Unable to create preferences file " + filename
  1760.     return
  1761.   end
  1762.   
  1763.   dim i as Integer
  1764.   dim s as String
  1765.   dim cnt as Integer = p.Count - 1
  1766.   dim a(-1) as String
  1767.   if cnt >= 0 then
  1768.     for i = 0 to cnt
  1769.       s = SaveFormat(p.Key(i))
  1770.       if s <> "" then a.Append s
  1771.     next
  1772.   end
  1773.   
  1774.   a.Sort
  1775.   cnt = UBound(a)
  1776.   if cnt >= 0 then
  1777.     for i = 0 to cnt
  1778.       fs.WriteLine a(i)
  1779.     next
  1780.   end
  1781.   fs.Close
  1782. End Sub
  1783.  
  1784. Pool.SaveGetFolder:
  1785. Private Function SaveGetFolder() As FolderItem
  1786.   dim f as FolderItem = PreferencesFolder.child(filename)
  1787.   if f <> Nil then return f
  1788.   
  1789.   f = GetFolderItem(filename)
  1790.   if f <> Nil then return f
  1791.   
  1792.   MsgBox "Unable to create preferences item " + filename
  1793.   return nil
  1794. End Function
  1795.  
  1796. Pool.SaveFormat:
  1797. Private Function SaveFormat(k as Variant) As String
  1798.   ' format the entry for writing
  1799.   dim t as String
  1800.   dim t2 as String
  1801.   dim v as String
  1802.   
  1803.   if not m.HasKey(k) then return ""     '  not marked for saving
  1804.   
  1805.   dim vb as Boolean
  1806.   dim vc as Color
  1807.   dim vd as Double
  1808.   dim vf as FolderItem
  1809.   dim vi as Integer
  1810.   dim vs as String
  1811.   
  1812.   dim i as Integer
  1813.   dim c as String
  1814.   dim isbin as Boolean
  1815.   
  1816.   dim d as Variant = p.Value(k)
  1817.   if d.Type = kBoolean then     ' boolean
  1818.     t = "b"
  1819.     t2 = "-"
  1820.     vb = d
  1821.     if vb then
  1822.       v = "true"
  1823.     else
  1824.       v = "false"
  1825.     end
  1826.     ' bin handled under string
  1827.   elseif d.Type = kColor then     ' color
  1828.     t = "c"
  1829.     t2 = "-"
  1830.     vc = d
  1831.     v = Fin.ColorToString(d)
  1832.   elseif d.Type = kDouble then     ' double
  1833.     t = "c"
  1834.     t2 = "-"
  1835.     vd = d
  1836.     v = Fin.formatFixedLong(d)
  1837.   elseif d.Type = kObject then     ' folder item
  1838.     t = "f"
  1839.     t2 = "-"
  1840.     vf = d
  1841.     v = EncodeBase64(vf.GetSaveInfo(nil, 0))
  1842.   elseif d.Type = kInteger then     ' integer
  1843.     t = "i"
  1844.     t2 = "-"
  1845.     vi = d
  1846.     v = Str(vi)
  1847.   elseif d.Type = kString then     ' string (and bin)
  1848.     if b.HasKey(k) and b.Value(k) = 1 then
  1849.       t = "bin"
  1850.       t2 = "-"
  1851.       vs = d
  1852.       v = EncodeBase64(vs)
  1853.     else
  1854.       t = "s"
  1855.       vs = d
  1856.       t2 = Fin.EncodingToString(vs.Encoding)
  1857.       isbin = false
  1858.       for i = 1 to Len(vs)
  1859.         c = vs.Mid(i, 1)
  1860.         if c < Fin.SPACE or c > "~" then
  1861.           isbin = true
  1862.           break
  1863.         end
  1864.       next
  1865.       if isbin then
  1866.         t = "sb"
  1867.         v = EncodeBase64(vs)
  1868.       else
  1869.         v = vs
  1870.       end
  1871.     end
  1872.   else
  1873.     t = "unk"
  1874.     t2 = "-"
  1875.     v = "-"
  1876.   end
  1877.   return k + Fin.TAB + t + Fin.TAB + t2 + Fin.TAB + v
  1878. End Function
  1879.  
  1880. Pool.ReloadItem:
  1881. Private Sub ReloadItem(s as String)
  1882.   dim a(-1) as String = s.Split(Fin.TAB)
  1883.   if UBound(a) <> 3 then return    ' format error
  1884.   
  1885.   dim vb as Boolean
  1886.   dim vc as Color
  1887.   dim vd as Double
  1888.   dim vf as FolderItem
  1889.   dim vi as Integer
  1890.   dim vs as String
  1891.   
  1892.   if a(1) = "b" then
  1893.     if a(3) = "true" then
  1894.       vb = true
  1895.     else
  1896.       vb = false
  1897.     end
  1898.     p.Value(a(0)) = vb
  1899.   elseif a(1) = "bin" then
  1900.     vs = DecodeBase64(a(3))
  1901.     vs = vs.DefineEncoding(nil)
  1902.     p.Value(a(0)) = vs
  1903.   elseif a(1) = "c" then
  1904.     vc = Fin.StringToColor(a(3))
  1905.     p.Value(a(0)) = vc
  1906.   elseif a(1) = "d" then
  1907.     vd = CDbl(a(3))
  1908.     p.Value(a(0)) = vd
  1909.   elseif a(1) = "f" then
  1910.     vf = GetFolderItem(DecodeBase64(a(3)))
  1911.     p.Value(a(0)) = vf
  1912.   elseif a(1) = "i" then
  1913.     vi = Val(a(3))
  1914.     p.Value(a(0)) = vi
  1915.   elseif a(1) = "s" then
  1916.     vs = a(3)
  1917.     vs = vs.DefineEncoding(Fin.StringToEncoding(a(2)))
  1918.     p.Value(a(0)) = vs
  1919.   elseif a(1) = "sb" then
  1920.     vs = DecodeBase64(a(3))
  1921.     vs = vs.DefineEncoding(Fin.StringToEncoding(a(2)))
  1922.     p.Value(a(0)) = vs
  1923.   else
  1924.     MsgBox "Unknown code '" + a(1) + "' found in Preferences...skipping"
  1925.     return     ' unknown code
  1926.   end
  1927. End Sub
  1928.  
  1929. Fin.Init:
  1930. Protected Function Init(adomain as String,  aname as String, astring as String) As Boolean
  1931.   ' domain is the preference domain
  1932.   ' appname is the name of the application as you want it displayed
  1933.   ' appstring is the name of the application with spaces and special characters removed
  1934.   ' version is the version string of the form #.#
  1935.   
  1936.   #if TargetWin32 then
  1937.     NL = Chr(13) + Chr(10)
  1938.     TargetSystem = "win"
  1939.   #endif
  1940.   #if TargetMacOS then
  1941.     NL = Chr(13)
  1942.     #if TargetCarbon then
  1943.       TargetSystem = "osx"
  1944.     #else
  1945.       TargetSystem = "os9"
  1946.     #endif
  1947.   #endif
  1948.   #if TargetLinux then
  1949.     NL = Chr(10)
  1950.     TargetSystem = "linux"
  1951.   #endif
  1952.   SPACE = "  "
  1953.   TAB = Chr(9)
  1954.   CR = Chr(13)
  1955.   LF = Chr(10)
  1956.   
  1957.   AppDomain = adomain
  1958.   AppName = aname
  1959.   AppString = astring
  1960.   AppVersion = Str(App.MajorVersion) + "." + Str(App.MinorVersion)
  1961.   AppLongVersion = AppVersion + "." + Str(App.BugVersion)
  1962.   
  1963.   FeedbackURL = "mailto:craig@finseth.com?subject=" + AppName + " " + AppVersion
  1964.   FeedbackURL = ReplaceAll(FeedbackURL, " ", "%20")
  1965.   
  1966.   'AppManualURL = GetFolderItem("").AbsolutePath + AppName + ".html"
  1967.   '#if TargetMacOS then
  1968.   'dim i as Integer = AppManualURL.InStr(":")
  1969.   'if i > 0 then AppManualURL = AppManualURL.Mid(i)
  1970.   'AppManualURL = AppManualURL.ReplaceAll(":", "/")
  1971.   '#endif
  1972.   '#if TargetWin32 then
  1973.   'AppManualURL = AppManualURL.ReplaceAll("\", "/")
  1974.   '#endif
  1975.   'AppManualURL = "file://" + AppManualURL.ReplaceAll(" ", "%20")
  1976.   'MsgBox "manual <" + fin.AppManualURL + ">"
  1977.   AppManualName = AppName + ".html"
  1978.   
  1979.   VersionURL = "http://www.finseth.com/versions/index.xml"
  1980.   
  1981.   printerSettings = ""
  1982.   pageSetupCalled = false
  1983.   
  1984.   if not Pool.Init(AppDomain, AppString) then return false
  1985.   
  1986.   dim s as String
  1987.   if Pool.GetBin("Fin.printerSettings", s) then printerSettings = s
  1988.   return true
  1989. End Function
  1990.  
  1991. Fin.WindowCenter:
  1992. Protected Sub WindowCenter(w as Window)
  1993.   ' center the window on the screen
  1994.   #if TargetWin32 then
  1995.     #if IsMDH then
  1996.       w.Left = (MDIWindow.Width - w.Width) / 2
  1997.       w.Top = (MDIWindow.Height - w.Height) / 2
  1998.     #else
  1999.       w.Left = (Screen(0).AvailableWidth - w.Width) / 2
  2000.       w.Top = (Screen(0).AvailableHeight - w.Height) / 2
  2001.     #endif
  2002.   #else
  2003.     w.Left = (Screen(0).AvailableWidth - w.Width) / 2
  2004.     w.Top = (Screen(0).AvailableHeight - w.Height) / 2
  2005.   #endif
  2006. End Sub
  2007.  
  2008. Fin.WindowSane:
  2009. Protected Sub WindowSane(w as Window)
  2010.   ' ensure that the window fits on the screen
  2011.   dim margin as Integer = 30
  2012.   dim sal, sat, sah, saw as Integer
  2013.   
  2014.   #if TargetWin32 then
  2015.     #if IsMDH then
  2016.       sal = 0
  2017.       sat = 0
  2018.       saw = MDIWindow.Width
  2019.       sah = MDIWindow.Height
  2020.     #else
  2021.       sal = Screen(0).AvailableLeft
  2022.       sat = Screen(0).AvailableTop
  2023.       sah = Screen(0).AvailableHeight
  2024.       saw = Screen(0).AvailableWidth
  2025.     #endif
  2026.   #else
  2027.     sal = Screen(0).AvailableLeft
  2028.     sat = Screen(0).AvailableTop
  2029.     sah = Screen(0).AvailableHeight
  2030.     saw = Screen(0).AvailableWidth
  2031.   #endif
  2032.   if w.Left < sal + margin then w.Left = sal + margin
  2033.   if w.Left > sal + saw - margin then w.Left = sal + saw - margin
  2034.   if w.Top < sat + margin then w.Top = sat + margin
  2035.   if w.Top > sat + sah - margin then w.Top = sat + sah - margin
  2036.   if w.Left + w.Width + margin > saw then w.Width = saw - margin - w.Left
  2037.   if w.Top + w.Height + margin > sah then w.Height = sah - margin - w.Top
  2038. End Sub
  2039.  
  2040. Fin.formatFixed:
  2041. Protected Function formatFixed(x as Double) As String
  2042.   ' like Format, but formats more intelligently
  2043.   dim ax as Double
  2044.   dim s as String
  2045.   ax = abs(x)
  2046.   
  2047.   if ax = 0 then
  2048.     return "0"
  2049.   elseif ax > 10000000000 or ax < 0.000000001 then
  2050.     return Format(x, "-#.##########e-")
  2051.   else
  2052.     s = Format(x, "-#######,###.##########")
  2053.     if Right(s, 1) = "." then
  2054.       s = Left(s, Len(s) - 1)
  2055.     end
  2056.     return s
  2057.   end
  2058. End Function
  2059.  
  2060. Fin.formatMemory:
  2061. Protected Function formatMemory(x as Double) As String
  2062.   ' format a memory value
  2063.   dim s as String = ""
  2064.   dim xx as Double = x
  2065.   
  2066.   if x < 0 then
  2067.     xx = -xx
  2068.     s = "-"
  2069.   end
  2070.   if xx < 1024 then
  2071.     return s + formatFixed(xx) + " B"
  2072.   elseif xx < 1024 * 1024 then
  2073.     return s + formatFixed(xx / 1024) + " KB"
  2074.   elseif xx < 1024 * 1024 * 1024 then
  2075.     return s + formatFixed(xx / (1024 * 1024)) + " MB"
  2076.   else
  2077.     return s + formatFixed(xx / (1024 * 1024 * 1024)) + " GB"
  2078.   end
  2079. End Function
  2080.  
  2081. Fin.Hex2:
  2082. Protected Function Hex2(x as Integer) As String
  2083.   ' return X as a 2-digit hex string
  2084.   dim s as String
  2085.   s = Lowercase(Hex(x))
  2086.   if Len(s) < 2 then
  2087.     return "0" + s
  2088.   else
  2089.     return s
  2090.   end
  2091. End Function
  2092.  
  2093. Fin.R3:
  2094. Protected Function R3(x as Double) As Double
  2095.   ' round to 3 decimal places
  2096.   return Floor(x * 1000) / 1000
  2097. End Function
  2098.  
  2099. Fin.SplitOff:
  2100. Protected Function SplitOff(c as String, byref s as String) As String
  2101.   ' return the first part of S up to but not including C; remove the returned data and C from S
  2102.   dim i as Integer = InStr(s, c)
  2103.   dim r as String
  2104.   
  2105.   if i <= 0 then
  2106.     r = s
  2107.     s = ""
  2108.     return r
  2109.   end
  2110.   r = Left(s, i - 1)
  2111.   s = Mid(s, i + 1)
  2112.   return r
  2113. End Function
  2114.  
  2115. Fin.SToN:
  2116. Protected Function SToN(s as String, b as Integer) As Integer
  2117.   ' treat S as an integer in base B (2 <= B <= 36) and return the value
  2118.   dim x as String = Lowercase(s)
  2119.   dim ret as integer
  2120.   dim c as integer
  2121.   
  2122.   while Len(x) > 0
  2123.     c = Asc(x)
  2124.     if c >= 48 and c <= 57 then
  2125.       ret = ret * b + (c - 48)
  2126.     elseif c >= 97 and c <= 102 then
  2127.       ret = ret * b + (c - 97 + 10)
  2128.     end
  2129.     x = Mid(x, 2)
  2130.   wend
  2131.   return ret
  2132. End Function
  2133.  
  2134. Fin.SToColor:
  2135. Protected Function SToColor(s as String) As Color
  2136.   ' S is RRGGBB form with RR, GG, and BB in hex
  2137.   return RGB(SToN(Left(s, 2), 16), SToN(Mid(s, 3, 2), 16), SToN(Mid(s, 5), 16))
  2138. End Function
  2139.  
  2140. Fin.StringToColor:
  2141. Protected Function StringToColor(s as String) As Color
  2142.   return RGB(SToN(Left(s, 2), 16), SToN(Mid(s, 3, 2), 16), SToN(Mid(s, 5, 2), 16))
  2143. End Function
  2144.  
  2145. Fin.ValE:
  2146. Protected Function ValE(s as String) As Double
  2147.   ' s is a number that can be in exponential form: convert it to a double
  2148.   dim m as String
  2149.   dim e as String
  2150.   dim mv as Double
  2151.   dim ev as Integer
  2152.   dim pv as Double
  2153.   dim i as Integer
  2154.   e = s
  2155.   m = SplitOff("e", e)
  2156.   if m = "" then
  2157.     m = "0"
  2158.     e = "0"
  2159.   end
  2160.   if e = "" then
  2161.     e = "0"
  2162.   end
  2163.   mv = Val(m)
  2164.   pv = 1
  2165.   ev = Val(e)
  2166.   if ev < 0 then
  2167.     ev = -ev
  2168.     for i = 1 to ev
  2169.       pv = pv * 10
  2170.     next
  2171.     pv = 1 / pv
  2172.   else
  2173.     for i = 1 to ev
  2174.       pv = pv * 10
  2175.     next
  2176.   end
  2177.   return mv * pv
  2178. End Function
  2179.  
  2180. Fin.InterpolateColor:
  2181. Protected Function InterpolateColor(c1 as Color, c2 as Color, i as Integer, n as Integer) As Color
  2182.   ' return the color that is i/n of the way from c1 to c2
  2183.   dim r, g, b as Integer
  2184.   r = c1.Red * (n - i) / n + c2.Red * i / n
  2185.   g = c1.Green * (n - i) / n + c2.Green * i / n
  2186.   b = c1.Blue * (n - i) / n + c2.Blue * i / n
  2187.   return RGB(r, g, b)
  2188. End Function
  2189.  
  2190. Fin.ColorToString:
  2191. Protected Function ColorToString(c as Color) As String
  2192.   return Hex2(c.Red) + Hex2(c.Green) + Hex2(c.Blue)
  2193. End Function
  2194.  
  2195. Fin.f2:
  2196. Protected Function f2(i as Integer) As String
  2197.   ' format i as a string ensuring that it is at least 2 digits long with 0 fill
  2198.   dim s as String = Str(i)
  2199.   if Len(s) < 2 then
  2200.     return "0" + s
  2201.   else
  2202.     return s
  2203.   end
  2204. End Function
  2205.  
  2206. Fin.f2s:
  2207. Protected Function f2s(i as Integer) As String
  2208.   ' format i as a string ensuring that it is at least 2 digits long with space fill
  2209.   dim s as String = Str(i)
  2210.   if Len(s) < 2 then
  2211.     return " " + s
  2212.   else
  2213.     return s
  2214.   end
  2215. End Function
  2216.  
  2217. Fin.formatBase:
  2218. Protected Function formatBase(x as Integer, b as Integer) As String
  2219.   ' format x in base b
  2220.   dim result as String = ""
  2221.   dim wasneg as Boolean = false
  2222.   dim xx as Integer = x
  2223.   dim c as Integer
  2224.   
  2225.   if xx = 0 then
  2226.     return "0"
  2227.   end
  2228.   
  2229.   if xx < 0 then
  2230.     wasneg = true
  2231.     xx = -xx
  2232.   end
  2233.   
  2234.   while xx > 0
  2235.     c = xx mod b
  2236.     if c >= 10 then
  2237.       result = Chr(c - 10 + 97) + result
  2238.     else
  2239.       result = Chr(c + 48) + result
  2240.     end
  2241.     xx = xx / b
  2242.   wend
  2243.   
  2244.   if wasneg then result = "-" + result
  2245.   
  2246.   return result
  2247. End Function
  2248.  
  2249. Fin.formatCarat:
  2250. Protected Function formatCarat(c as String) As String
  2251.   '  format the first character of c using ^ notation
  2252.   dim i as Integer
  2253.   dim v as Integer
  2254.   dim outs as String = ""
  2255.   dim cc as String = c
  2256.   
  2257.   if LenB(cc) > 1 then
  2258.     v = 0
  2259.     for i = 1 to LenB(cc) - 1
  2260.       v = v * 256 + AscB(MidB(cc, i, 1))
  2261.     next
  2262.     cc = RightB(cc, 1)
  2263.     outs = formatBase(v, 16) + "+"
  2264.   end
  2265.   i = AscB(cc)
  2266.   if i >= 128 then
  2267.     outs = outs + "~"
  2268.     i = i - 128
  2269.   end
  2270.   if i < 32 then
  2271.     outs = outs + "^"
  2272.     i = i + 64
  2273.   end
  2274.   if i = 127 then
  2275.     outs = outs + "^"
  2276.     i = i - 64
  2277.   end
  2278.   outs = outs + Chr(i)
  2279.   return outs
  2280. End Function
  2281.  
  2282. Fin.formatFixedLong:
  2283. Protected Function formatFixedLong(x as Double) As String
  2284.   ' like formatFixed, but makes longer number
  2285.   dim ax as Double = Abs(x)
  2286.   dim s as String
  2287.   
  2288.   if ax = 0 then
  2289.     return "0"
  2290.   elseif ax > 10000000000 or ax < 0.000000001 then
  2291.     return Format(x, "-#.###############e-")
  2292.   else
  2293.     s = Format(x, "-#######,###.###############")
  2294.     if Right(s, 1) = "." then
  2295.       s = Left(s, Len(s) - 1)
  2296.     end
  2297.     return s
  2298.   end
  2299. End Function
  2300.  
  2301. Fin.GCD:
  2302. Protected Function GCD(a as Integer, b as Integer) As Integer
  2303.   ' greatest common divisor
  2304.   dim x, y as Integer
  2305.   dim aa as Integer = a
  2306.   dim bb as Integer = b
  2307.   
  2308.   if aa = bb then return aa
  2309.   
  2310.   if aa <= 0 or bb <= 0 then return 1
  2311.   
  2312.   if bb > aa then return GCD(bb, aa)
  2313.   
  2314.   while true
  2315.     x = aa mod bb
  2316.     if x = 0 then return bb
  2317.     
  2318.     y = Floor(bb / x)
  2319.     if bb = y * x then return x
  2320.     
  2321.     aa = bb
  2322.     bb = x
  2323.   wend
  2324. End Function
  2325.  
  2326. Fin.StringToEncoding:
  2327. Protected Function StringToEncoding(s as String) As TextEncoding
  2328.   dim b as Integer = 0
  2329.   dim v as Integer = 0
  2330.   dim f as Integer = 0
  2331.   dim a(-1) as String = s.Split(",")
  2332.   if UBound(a) = 2 then
  2333.     b = Val(a(0))
  2334.     v = Val(a(1))
  2335.     f = Val(a(2))
  2336.   end
  2337.   return GetTextEncoding(b, v, f)
  2338. End Function
  2339.  
  2340. Fin.EncodingToString:
  2341. Protected Function EncodingToString(e as TextEncoding) As String
  2342.   return Str(e.Base) + "," + Str(e.Variant) + "," + Str(e.Format)
  2343. End Function
  2344.  
  2345. Fin.FormatMemoryNice:
  2346. Protected Function FormatMemoryNice(x as Double) As String
  2347.   ' format a memory value but make it look nice
  2348.   dim s as String = ""
  2349.   dim xx as Double = x
  2350.   
  2351.   if x < 0 then
  2352.     xx = -xx
  2353.     s = "-"
  2354.   end
  2355.   if xx < 1024 then
  2356.     return s + CStr(R3(x)) + " Byte(s)"
  2357.   elseif xx < 1024 * 1024 then
  2358.     return s + CStr(R3(xx / 1024)) + " KBytes"
  2359.   elseif xx < 1024 * 1024 * 1024 then
  2360.     return s + CStr(R3(xx / (1024 * 1024))) + " MBytes"
  2361.   else
  2362.     return s + CStr(R3(xx / (1024 * 1024 * 1024))) + " GBytes"
  2363.   end
  2364. End Function
  2365.  
  2366. Fin.LaunchFile:
  2367. Protected Sub LaunchFile(s as String)
  2368.   dim f as FolderItem = GetFolderItem(s)
  2369.   if f <> nil then f.Launch
  2370. End Sub
  2371.  
  2372. Fin.PageSetup:
  2373. Protected Sub PageSetup()
  2374.   dim ps as PrinterSetup
  2375.   ps = new PrinterSetup
  2376.   if printerSettings = "" then
  2377.     ps.MaxVerticalResolution = -1
  2378.     ps.MaxHorizontalResolution = -1
  2379.   else
  2380.     ps.SetupString = printerSettings
  2381.   end
  2382.   if ps.PageSetupDialog then
  2383.     printerSettings = ps.setupString
  2384.     Pool.SetBin("Fin.printerSettings", printerSettings)
  2385.     pageSetupCalled = true
  2386.   end
  2387. End Sub
  2388.  
  2389. Fin.PrintIt:
  2390. Protected Function PrintIt() As PrinterSetup
  2391.   dim ps as PrinterSetup 
  2392.   ps = new PrinterSetup
  2393.   if ps = nil then return nil
  2394.   
  2395.   if not pageSetupCalled then PageSetup
  2396.   ps.SetupString = printerSettings
  2397.   Pool.SetBin("Fin.printerSettings", printerSettings)
  2398. End Function
  2399.  
  2400. Fin.ImageSizer:
  2401. Protected Sub ImageSizer(srcWidth as Integer, srcHeight as Integer, destWidth as Integer, destHeight as Integer)
  2402.   ' Fit the src image into the destination size and set the Image* values accordingly.
  2403.   ImageLeft = 0
  2404.   ImageTop = 0
  2405.   ImageWidth = destWidth
  2406.   ImageHeight = destHeight
  2407.   dim r as Double
  2408.   
  2409.   if srcWidth > srcHeight then     ' landscape
  2410.     r = srcHeight
  2411.     r = r / srcWidth
  2412.     ImageTop = (ImageHeight - r * ImageHeight) / 2
  2413.     ImageHeight = ImageHeight * r
  2414.   elseif srcWidth < srcHeight then     ' portrait
  2415.     r = srcWidth
  2416.     r = r / srcHeight
  2417.     ImageLeft = (ImageWidth - r * ImageWidth) / 2
  2418.     ImageWidth = ImageWidth * r
  2419.   else     ' square
  2420.   end
  2421. End Sub
  2422.  
  2423. Fin.PrintOpen:
  2424. Protected Function PrintOpen(ps as PrinterSetup, lm as Integer, tm as Integer, rm as Integer, bm as Integer) As Graphics
  2425.   ' lm is the preferred left margin in inches, tm is top, rm is right and bm is bottom
  2426.   
  2427.   ' Initialize the printer and set the Printer* margins according to the minimums supported by the
  2428.   ' printer and the passed values.  Return the printerSettings on success or nil on error
  2429.   
  2430.   dim g as Graphics = OpenPrinterDialog(ps)
  2431.   if g = nil then return nil
  2432.   printerSettings = ps.SetupString
  2433.   Pool.SetBin("Fin.printerSettings", printerSettings)
  2434.   
  2435.   ' The PrinterSetup has Left, Top, Width and Height values.  The Left and Top values are adjusted
  2436.   ' so that (0, 0) is where you start printing.  I.e., the Left and Top values will be negative or 0.
  2437.   
  2438.   ' Calculate left margin.  It is the greater of the printer left margin and the supplied lm value.
  2439.   dim x as Integer = lm * ps.HorizontalResolution
  2440.   PrinterLeft = 0
  2441.   if x > (- ps.PageLeft) then PrinterLeft = x - (- ps.PageLeft)
  2442.   
  2443.   PrinterWidth = ps.PageWidth
  2444.   x = rm * ps.HorizontalResolution
  2445.   dim y as Integer = ps.PageWidth - ps.Width - (-ps.PageLeft) - PrinterLeft     ' y is now the right margin
  2446.   if x > y then PrinterWidth = PrinterWidth - (x - y)
  2447.   
  2448.   ' now do top/bottom margins
  2449.   x = tm * ps.VerticalResolution
  2450.   PrinterTop = 0
  2451.   if x > (- ps.PageTop) then PrinterTop = x - (- ps.PageTop)
  2452.   
  2453.   PrinterHeight = ps.PageHeight
  2454.   x = bm * ps.VerticalResolution
  2455.   y = ps.PageHeight - ps.Height - (-ps.PageTop) - PrinterTop
  2456.   if x > y then PrinterHeight = PrinterHeight - (x - y)
  2457.   
  2458.   PrinterScale = ps.VerticalResolution / 72
  2459.   
  2460.   ' now print using (Fin.PrinterLeft, Fin.PrintTop) as the top left corner and Fin.PrinterWidth and Fin.PrinterHeight
  2461.   ' as the page size
  2462.   'MsgBox "ps.PW=" + str(ps.PageWidth) + ", ps.PH=" + str(ps.PageHeight) + Fin.NL + "ps.PL=" + str(ps.PageLeft) + ", ps.PT=" + str(ps.PageTop) + ", ps.W=" + str(ps.Width) + ",  ps.H=" + str(ps.Height) + Fin.NL + "ps.HR=" + str(ps.HorizontalResolution) + ", ps.VR=" + str(ps.VerticalResolution) + Fin.NL + "PL=" + str(PrinterLeft) + ", PT=" + str(PrinterTop) + ", PW=" + str(PrinterWidth) + ", PH=" + str(PrinterHeight)
  2463.   return g
  2464. End Function
  2465.  
  2466. Fin.ToDeg:
  2467. Protected Function ToDeg(a as Double) As Double
  2468.   return a * 180 / PI
  2469. End Function
  2470.  
  2471. Fin.ToRad:
  2472. Protected Function ToRad(a as Double) As Double
  2473.   return a * PI / 180
  2474. End Function
  2475.  
  2476.